﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchMethodLibrary.Utils;
using YJKCodeBase.WinForm;

namespace YJKRamp.CreateRampByDoor
{
	public class PassagewayRampDesigner
	{
		public PassagewayRampDesigner(ExternalCommandData cmdData, ElementId materialId)
		{
			this.m_Revit = cmdData;
			this.m_RevitApp = this.m_Revit.Application.Application;
			this.m_MaterialId = materialId;
		}

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result DesignExtrusionRamp(ref string message)
		{
			DoorGeometryExtractor extractor = new DoorGeometryExtractor(this.m_Revit);
			PassagewayRampForm passagewayRampForm = new PassagewayRampForm(extractor);
			passagewayRampForm.Show(PassagewayRampDesigner._hWndRevit);
			int wMsg = 7;
			PassagewayRampDesigner.SendMessage(PassagewayRampDesigner._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			FamilyInstance door = null;
			while (this.SelDoor(ref door))
			{
				this.CreateRampByDoors(door, passagewayRampForm, ref message);
			}
			passagewayRampForm.Close();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private bool CreateRampByDoors(FamilyInstance door, PassagewayRampForm dlg, ref string message)
		{
			XYZ point = (door.Location as LocationPoint).Point;
			double num = door.Symbol.get_Parameter(BuiltInParameter.CASEWORK_WIDTH).AsDouble();
			ElementId elementId = door.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).AsElementId();
			Level level = this.m_Revit.Application.ActiveUIDocument.Document.GetElement(elementId) as Level;
			double elevation = level.Elevation;
			double num2 = door.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).AsDouble();
			XYZ facingOrientation = door.FacingOrientation;
			XYZ xyz = door.HandOrientation;
			if (door.Mirrored)
			{
				xyz = -xyz;
			}
			double num3 = 0.0;
			Wall wall = door.Host as Wall;
			if (wall != null)
			{
				num3 = wall.Width;
			}
			double rampLength = dlg.RampLength;
			double rampOffsetWidth = dlg.RampOffsetWidth;
			double rampBottomOffsetWidth = dlg.RampBottomOffsetWidth;
			double rampHeight = dlg.RampHeight;
			double rampVOffset = dlg.RampVOffset;
			double rampElevation = elevation + num2 - rampHeight + rampVOffset;
			double rampHOffset = dlg.RampHOffset;
			SkidResistanceType rampSkidResistanceType = dlg.RampSkidResistanceType;
			XYZ xyz2 = point + xyz * num / 2.0;
			xyz2 += facingOrientation * (num3 / 2.0);
			Line doorBottomEdge = YJKLineEx.YJKGetBound(XYZ.Zero, new XYZ(num, 0.0, 0.0));
			XYZ locationPoint = xyz2 + xyz * rampOffsetWidth;
			if (dlg.TheRampType == RampType.RT_Car)
			{
				locationPoint = xyz2 + xyz * rampBottomOffsetWidth;
			}
			string familiyPath = "";
			string familyName = "";
			string symbolName = "";
			this.DesignExtrusionRamp(dlg.TheRampType, doorBottomEdge, rampLength, rampOffsetWidth, rampBottomOffsetWidth, rampHeight, rampSkidResistanceType, ref familiyPath, ref familyName, ref symbolName, ref message);
			if (!this.LoadFamiliesFile(familiyPath, ref message))
			{
				return false;
			}
			double angle = Geometry.getAngle(XYZ.Zero, -XYZ.BasisY);
			double angle2 = Geometry.getAngle(XYZ.Zero, facingOrientation);
			double rotate = Geometry.BetweenTheAngles(angle, angle2, true);
			XYZ move = facingOrientation * rampHOffset;
			return this.CreateElement(locationPoint, rampElevation, rotate, move, familyName, symbolName, level, ref message);
		}

		private bool SelDoor(ref FamilyInstance door)
		{
			Reference reference = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				reference = selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new DoorFilter(), "选择门");
			}
			catch (Exception)
			{
				return false;
			}
			if (reference == null)
			{
				return false;
			}
			door = (this.m_Revit.Application.ActiveUIDocument.Document.GetElement(reference) as FamilyInstance);
			return true;
		}

		private bool DesignExtrusionRamp(RampType rampType, Line doorBottomEdge, double rampLength, double rampOffsetWidth, double rampBottomOffsetWidth, double rampHeight, SkidResistanceType srType, ref string familyFilePath, ref string familyName, ref string symbolName, ref string message)
		{
			Result result = this.OpenAndActiveFamilyTemplateDocument(ref message);
			if (result != Result.Succeeded)
			{
				return false;
			}
			Transaction transaction = new Transaction(this.m_FamilyDocument);
			transaction.Start("create family");
			this.m_FamilyCreator = new RampFamilyCreator(this.m_Revit, this.m_MaterialId, this.m_FamilyDocument);
			double rampWidth = doorBottomEdge.Length + rampOffsetWidth * 2.0;
			double rampBottomWidth = doorBottomEdge.Length + rampBottomOffsetWidth * 2.0;
			List<Curve> list = new List<Curve>();
			XYZ xyz = new XYZ(0.0, 0.0, 0.0);
			XYZ xyz2 = new XYZ(0.0, -rampLength, 0.0);
			XYZ xyz3 = new XYZ(0.0, 0.0, rampHeight);
			Line item = YJKLineEx.YJKGetBound(xyz2, xyz);
			list.Add(item);
			Line item2 = YJKLineEx.YJKGetBound(xyz, xyz3);
			list.Add(item2);
			Line item3 = YJKLineEx.YJKGetBound(xyz3, xyz2);
			list.Add(item3);
			List<XYZ> list2 = new List<XYZ>();
			XYZ xyz4 = (xyz3 - xyz2).Normalize();
			double length = (xyz3 - xyz2).GetLength();
			double num = Common.MMToFeet(60.0);
			int num2 = Common.GetInt(length / num) - 1;
			for (int i = 1; i <= num2; i++)
			{
				XYZ item4 = xyz2 + xyz4 * (num * (double)i);
				list2.Add(item4);
			}
			result = this.CreateExtrusionRamp(rampType, list, rampLength, rampWidth, rampBottomWidth, rampHeight, xyz4, list2, srType, ref symbolName, ref message);
			if (result != Result.Succeeded)
			{
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				this.DocumentClose();
				return false;
			}
			transaction.Commit();
			result = this.SaveFamilyFile(ref familyFilePath, ref familyName);
			if (result != Result.Succeeded)
			{
				this.DocumentClose();
				return false;
			}
			return true;
		}

		private Result CreateExtrusionRamp(RampType rampType, List<Curve> rampSection, double rampLength, double rampWidth, double rampBottomWidth, double rampHeight, XYZ slopeDir, List<XYZ> skidResistancePosition, SkidResistanceType srType, ref string symbolName, ref string message)
		{
			Result result = this.m_FamilyCreator.AddReferencePlanes(ref message);
			if (result != Result.Succeeded)
			{
				return result;
			}
			result = this.m_FamilyCreator.CreateExtrusionForm(rampType, rampSection, rampLength, rampWidth, rampBottomWidth, rampHeight, slopeDir, skidResistancePosition, srType, ref message);
			if (result != Result.Succeeded)
			{
				return result;
			}
			result = this.m_FamilyCreator.AddAlignments(ref message);
			if (result != Result.Succeeded)
			{
				return result;
			}
			result = this.m_FamilyCreator.AddParameters(ref message);
			if (result != Result.Succeeded)
			{
				return result;
			}
			result = this.m_FamilyCreator.AddDimensions(ref message);
			if (result != Result.Succeeded)
			{
				return result;
			}
			result = this.m_FamilyCreator.AddSymbols(ref symbolName, ref message);
			if (result != Result.Succeeded)
			{
				return result;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result OpenAndActiveFamilyTemplateDocument(ref string message)
		{
			string text = AssistFunc.GetAppRootPath();
			string versionNumber = this.m_Revit.Application.Application.VersionNumber;
			text = text + "\\Templates\\" + versionNumber + "\\RampFamilyTemplate.rft";
			if (!File.Exists(text))
			{
				throw new Exception("Unsupported version");
			}
			this.m_FamilyDocument = this.m_RevitApp.NewFamilyDocument(text);
			if (this.m_FamilyDocument == null)
			{
				message = "缺少族模板.";
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result SaveFamilyFile(ref string familyFilePath, ref string familyName)
		{
			int num = this.CalculateFamilyNumber();
			string tempPath = Path.GetTempPath();
			familyName = "入门坡道" + num.ToString();
			familyFilePath = tempPath + familyName + ".rfa";
			if (File.Exists(familyFilePath))
			{
				File.Delete(familyFilePath);
			}
			RevitVersionFuncs.SaveAs(this.m_FamilyDocument, familyFilePath);
			this.m_FamilyDocument.Close(true);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private int CalculateFamilyNumber()
		{
			string text = "入门坡道";
			int length = text.Length;
			List<int> list = new List<int>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Revit.Application.ActiveUIDocument.Document);
			IList<Element> list2 = filteredElementCollector.OfClass(typeof(Family)).ToElements();
			foreach (Element element in list2)
			{
				Family family = element as Family;
				if (family != null)
				{
					string name = family.Name;
					int num = name.IndexOf(text);
					if (num != -1)
					{
						string value = name.Substring(num + length, name.Length - num - length);
						int item = 0;
						try
						{
							item = Convert.ToInt32(value);
						}
						catch (Exception)
						{
							continue;
						}
						list.Add(item);
					}
				}
			}
			if (list.Count == 0)
			{
				return 1;
			}
			list.Sort();
			return list[list.Count - 1] + 1;
		}

		private void DocumentClose()
		{
			this.m_FamilyDocument.Close(false);
		}

		private bool LoadFamiliesFile(string familiyPath, ref string message)
		{
			Transaction transaction = new Transaction(this.m_Revit.Application.ActiveUIDocument.Document);
			transaction.Start("load families");
			this.m_Revit.Application.ActiveUIDocument.Document.LoadFamily(familiyPath);
			transaction.Commit();
			return true;
		}

		private bool CreateElement(XYZ locationPoint, double rampElevation, double rotate, XYZ move, string familyName, string symbolName, Level doorLevel, ref string message)
		{
			Transaction transaction = new Transaction(this.m_Revit.Application.ActiveUIDocument.Document);
			transaction.Start("create element");
			FamilySymbol familySymbolByName = this.GetFamilySymbolByName(familyName, symbolName);
			if (familySymbolByName == null)
			{
				transaction.RollBack();
				return false;
			}
			double num = rampElevation - doorLevel.Elevation;
			UnifiedModified.ActivateFamilySymbol(familySymbolByName);
			FamilyInstance familyInstance = this.m_Revit.Application.ActiveUIDocument.Document.Create.NewFamilyInstance(locationPoint, familySymbolByName, doorLevel, 0);
			if (familyInstance != null)
			{
				Parameter parameter = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM);
				if (parameter != null)
				{
					parameter.Set(num);
				}
				Line line = YJKLineEx.YJKGetUnBound(locationPoint, XYZ.BasisZ);
				familyInstance.Location.Rotate(line, rotate);
				familyInstance.Location.Move(move);
			}
			transaction.Commit();
			return true;
		}

		private FamilySymbol GetFamilySymbolByName(string familyName, string symbolName)
		{
			FamilySymbol result = null;
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_Revit.Application.ActiveUIDocument.Document);
			IList<Element> list = filteredElementCollector.OfClass(typeof(Family)).ToElements();
			foreach (Element element in list)
			{
				Family family = element as Family;
				if (family != null)
				{
					Category familyCategory = RevitVersionFuncs.GetFamilyCategory(family);
					if (familyCategory != null && familyName.ToUpper().CompareTo(family.Name.ToUpper()) == 0)
					{
						List<FamilySymbol> symbols = family.GetSymbols();
						foreach (FamilySymbol familySymbol in symbols)
						{
							if (symbolName.ToUpper().CompareTo(familySymbol.Name.ToUpper()) == 0)
							{
								return familySymbol;
							}
						}
						if (symbols.Count > 0)
						{
							return symbols[0];
						}
					}
				}
			}
			return result;
		}

		public static WindowHandle _hWndRevit;

		private ExternalCommandData m_Revit;

		private Document m_FamilyDocument;

		private RampFamilyCreator m_FamilyCreator;

		private ElementId m_MaterialId;

		private Application m_RevitApp;
	}
}
